import copy
import json
import uuid
import time
from typing import List
from typing import Union
from apis import api_routes
from flask import abort, g, request, jsonify
from security.decoration import certification
from sqlalchemy import and_
from models.order.tasks import Tasks
from models.product.routes import Routes
from models.facility.facility import Facility
from models.product.aircraft import Aircraft
from public.local import datetime_type
from models.product.craft import Craft
from models.product.craft import CraftInit
from public.contexts import context_logs


@api_routes.route("/aircraft", methods=["POST"])
@certification(auth=True, role=None)
def func_aircraft_post_api():
    """
    添加机种API, 完成API开发
    http://127.0.0.1:8080/api/aircraft
    Content-Type=application/json
    methods=["POST"]
    {
    "aircraft":        string  ****   机种名称
    "specification"    string         产品规格
    "route_id"         int     ****   对应的路径ID api/routes/aircraft GET key
    }
    :return:
        {'status': 4001, "msg": "已存在此机种，禁止重复添加"}
        {'status': 4002, "msg": "没有找到配方"}
        {'status': 4003, "msg": "没有找到工艺路劲"}
        {'status': 200, 'msg': "添加机种成功"}
    ---
    tags:
      - 机种管理
    """
    data: dict = request.get_json()
    aircraft: Union[str, None] = data.get("aircraft")
    specification: Union[str, None] = data.get("specification")
    route_id: Union[int, None] = data.get("route_id")

    if aircraft is None or len(aircraft) == 0:
        abort(400)
    db_aircraft: Union[Aircraft, None] = g.session.query(Aircraft).filter(Aircraft.aircraft == aircraft).first()
    if db_aircraft is not None:
        return jsonify({'status': 4001, "msg": "已存在此机种，禁止重复添加"})
    del db_aircraft

    db_route: Union[Routes, None] = g.session.query(Routes).filter(Routes.id == route_id).first()
    if db_route is None:
        return jsonify({'status': 4003, "msg": "没有找到工艺路劲"})

    if "-" not in aircraft:
        return jsonify({'status': 4004, "msg": "机种命名格式错误： 机种名称-配方编号"})

    number_data: bool = False
    # noinspection PyBroadException
    try:
        parm_data: list = aircraft.split("-")
        int(parm_data[len(parm_data) - 1])
        number_data: bool = True
    except Exception as e:
        number_data: bool = False

    if number_data is False:
        return jsonify({'status': 4005, "msg": "机种命名格式错误： 机种名称-配方编号, 配方编号为阿拉伯数字"})

    log_pram = {"aircraft": aircraft, "specification": specification, "route_id": route_id}
    context_logs(name="添加机种", obsolescence=None, data=json.dumps(log_pram))

    g.session.add(Aircraft(
        aircraft=aircraft, specification=specification,
        route_id=route_id, time=datetime_type()
    ))
    g.session.commit()
    db_aircraft: Union[Aircraft, None] = g.session.query(Aircraft).filter(Aircraft.aircraft == aircraft).first()
    db_aircraft_id = db_aircraft.id

    ft_ids_new = []
    route_new = json.loads(db_route.route)
    routes_new = route_new.get("data")
    for itr1 in routes_new:
        second_rts = itr1.get("ft_ids")
        for itr2 in second_rts:
            ft_ids_new.append(itr2)
    ft_ids_new = list(set(ft_ids_new))

    parm: dict = {"Bool": None, "Short": None, "Int": None, "Float": None, "String": None}
    parm_keys: list = list(parm.keys())

    for ft_id in ft_ids_new:
        db_craft_init: List[CraftInit] = g.session.query(CraftInit).filter(
                                            CraftInit.ft_id == ft_id
                                        ).order_by(CraftInit.id).all()

        for device_io in db_craft_init:
            if device_io.types in parm_keys:
                craft: Union[Craft, None] = g.session.query(Craft).filter(and_(
                                                Craft.aircraft_id == db_aircraft_id,
                                                Craft.facility_id == ft_id,
                                                Craft.address == device_io.address
                                            )).first()
                if craft is None:
                    g.session.add(Craft(
                        facility_id=ft_id,
                        aircraft_id=db_aircraft_id,
                        address=device_io.address,
                        types=device_io.types,
                        describe=device_io.describe,
                        write=None
                    ))
    g.session.commit()
    return jsonify({'status': 200, 'msg': "添加机种成功"})


@api_routes.route("/aircraft", methods=["GET"])
@certification(auth=True, role=None)
def func_aircraft_get_api():
    """
    获取机种列表, 做分页， 完成API开发
    http://127.0.0.1:8080/api/aircraft
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    "index"     int      ****  第几页，默认为1
    "size"      int      ****  每页数据多少, 默认每页10条数据
    "aircraft"  string         机种名称，支持模糊查询
    "ft_id"      int           设备ID, 要是没有数据，则是返回第一个工站数据
    }
    :return:
        {'status': 200, 'data': resp}
    ---
    tags:
      - 机种管理
    """
    size: int = request.args.get("size", default=10, type=int)
    index: int = request.args.get("index", default=1, type=int)
    aircraft: Union[str, None] = request.args.get("aircraft", default=None, type=str)
    parm_ft_id: Union[int, None] = request.args.get("ft_id", default=None, type=int)

    if aircraft is not None and len(aircraft) == 0:
        aircraft = None

    count = g.session.query(Aircraft.id).count()
    if aircraft is not None:
        count = g.session.query(Aircraft.id).filter(Aircraft.aircraft.like("%" + aircraft + "%")).count()
    page: int = int((count / size) + 1) if (count / size) > int(count / size) else int(count / size)

    rsp: list = []
    db_aircraft: List[Aircraft] = g.session.query(Aircraft).order_by(Aircraft.id).offset((index - 1) * size).limit(size).all()
    if aircraft is not None:
        db_aircraft: List[Aircraft] = g.session.query(Aircraft).filter(
                                        Aircraft.aircraft.like("%" + aircraft + "%")
                                    ).order_by(Aircraft.id).all()

    db_aircraft_id: int = 0
    db_task_0: Union[Tasks, None] = g.session.query(Tasks).filter(Tasks.status == 't').first()
    if db_task_0 is not None:
        db_aircraft_0: Aircraft = g.session.query(Aircraft).filter(Aircraft.id == db_task_0.aircraft_id).first()
        db_aircraft_id = db_aircraft_0.id

    for index0, itr0 in enumerate(db_aircraft):
        ft_ids: list = []
        db_route: Routes = g.session.query(Routes).filter(Routes.id == itr0.route_id).first()

        route: dict = json.loads(db_route.route)
        routes = route.get("data")
        for index1, itr1 in enumerate(routes):
            second_rts: list = itr1.get("ft_ids")
            for itr2 in second_rts:
                ft_ids.append(itr2)
        ft_ids: list = list(set(ft_ids))

        if parm_ft_id is None and len(ft_ids) != 0:
            parm_ft_id = ft_ids[0]

        allows: list = []
        for itr4 in ft_ids:
            facility: Facility = g.session.query(Facility).filter(Facility.id == itr4).first()
            allows.append({
                "key": itr4,
                "value": facility.name
            })

        rsp.append({
            "aircraft_id": itr0.id,
            "aircraft": itr0.aircraft,
            "specification": itr0.specification,
            "route_id": itr0.route_id,
            "route_name": db_route.name,
            "time": itr0.time.strftime("%Y-%m-%d %H:%M:%S") if itr0.time else None,
            "allows": copy.deepcopy(allows),
            "in_production": True if db_aircraft_id == itr0.id else False
        })

    doc: dict = {
        "aircraft_id": "机种数据库ID",
        "aircraft": "机种名称",
        "specification": "机种规格",
        "route_id": "对应路径ID",
        "route_name": "对应路径名称",
        "time": "时间",
        "crafts": "工艺参数",
        "allows": "允许添加",
        "in_production": "是否在生产中"
    }
    return jsonify({'status': 200, 'data': rsp, "index": index, "size": size, "total": count, "page": page, "doc": doc})


@api_routes.route("/aircraft/ft_id", methods=["GET"])
@certification(auth=True, role=None)
def func_aircraft_ft_id_get_api():
    """
    按照机种ID,设备ID查询设备IO详细信息， 完成API开发
    http://127.0.0.1:8080/api/aircraft/ft_id
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    "aircraft_id"  int    ****    机种数据库ID
    "ft_id"        int    ****    设备ID, 要是没有数据，则是返回第一个工站数据
    }
    :return:
        {'status': 4001, "msg": "没找到机种"}
        {'status': 4002, "msg": "没找到工站"}
        {'status': 4003, "msg": "工站参数错误"}
        {'status': 200, 'data': array[dict], "docs": dict}
    ---
    tags:
      - 机种管理
    """
    aircraft_id: Union[int, None] = request.args.get("aircraft_id", default=0, type=int)
    parm_ft_id: Union[int, None] = request.args.get("ft_id", default=0, type=int)
    if not all([aircraft_id, parm_ft_id]):
        abort(400)
    db_aircraft: Union[Aircraft, None] = g.session.query(Aircraft).filter(Aircraft.id == aircraft_id).first()
    if db_aircraft is None:
        return jsonify({'status': 4001, "msg": "没找到机种"})

    facility: Union[Facility, None] = g.session.query(Facility).filter(Facility.id == parm_ft_id).first()
    if facility is None:
        return jsonify({'status': 4002, "msg": "没找到工站"})

    data: List[Craft] = g.session.query(Craft).filter(and_(
                            Craft.facility_id == parm_ft_id,
                            Craft.aircraft_id == aircraft_id
                        )).order_by(Craft.id).all()
    crafts: list = []
    for craft in data:
        crafts.append({
            "facility_id": facility.id,
            "facility_name": facility.name,
            "describe": craft.describe,
            "write": craft.write,
            "craft_id": craft.id,
            "address": craft.address,
            "types": craft.types
        })
    doc: dict = {
        "aircraft_id": "机种数据库ID",
        "aircraft": "机种名称",
        "specification": "机种规格",
        "route_id": "对应路径ID",
        "route_name": "对应路径名称",
        "time": "时间",
        "crafts": "工艺参数",
        "allows": "允许添加",
        "in_production": "是否在生产中",
        "edit": "是否可以编辑上下限"
    }
    return jsonify({'status': 200, 'data': crafts, "docs": doc})


@api_routes.route("/aircraft/all", methods=["GET"])
@certification(auth=True, role=None)
def func_aircraft_all_get_api():
    """
    获取全部机种, 没做分页（机种顶多二三十种）， 完成API开发
    http://127.0.0.1:8080/api/aircraft/all
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    }
    :return:
        {'status': 200, 'data': resp}
    ---
    tags:
      - 机种管理
    """
    resp: list = []
    aircraft: List[Aircraft] = g.session.query(Aircraft).order_by(Aircraft.id).all()
    for index0, itr0 in enumerate(aircraft):
        resp.append({
            "key": itr0.id,
            "value": itr0.aircraft,
        })
    return jsonify({'status': 200, 'data': resp})


@api_routes.route("/aircraft", methods=["PUT"])
@certification(auth=True, role=None)
def func_aircraft_put_api():
    """
    修改机种, 完成API开发
    http://127.0.0.1:8080/api/aircraft
    Content-Type=application/json
    methods=["GET"]
    {
    "aircraft_id":     int       ****  机种数据库ID
    "aircraft":        string          机种名称
    "specification"    string          产品规格
    "route_id"         int             对应的路径ID api/routes/aircraft GET key
    }
    :return:
        {'status': 200, 'data': resp}
    ---
    tags:
      - 机种管理
    """
    data: dict = request.get_json()
    aircraft_id: Union[int, None] = data.get("aircraft_id")
    route_id: Union[int, None] = data.get("route_id")
    aircraft: Union[str, None] = data.get("aircraft")
    specification: Union[str, None] = data.get("specification")

    if aircraft_id is None:
        abort(400)
    db_aircraft: Union[Aircraft, None] = g.session.query(Aircraft).filter(Aircraft.id == aircraft_id).first()
    if db_aircraft is None:
        return jsonify({'status': 4001, "msg": "客户端错误，未找到机种"})

    log_pram: dict = {
        "aircraft": aircraft,
        "specification": specification,
        "route_id": route_id
    }
    context_logs(name="修改机种", obsolescence=db_aircraft.__repr__(), data=json.dumps(log_pram))

    if aircraft is not None and aircraft != db_aircraft.aircraft:
        db_aircraft2: Union[Aircraft, None] = g.session.query(Aircraft).filter(Aircraft.aircraft == aircraft).first()
        if db_aircraft2 is not None:
            return jsonify({'status': 4002, "msg": "已存在此机种，禁止修改"})

        parm_data: list = aircraft.split("-")
        if "-" not in aircraft:
            return jsonify({'status': 4004, "msg": "机种命名格式错误： 机种名称-配方编号"})

        number_data: bool = False
        # noinspection PyBroadException
        try:
            int(parm_data[len(parm_data) - 1])
            number_data: bool = True
        except Exception as e:
            number_data: bool = False

        if number_data is False:
            return jsonify({'status': 4005, "msg": "机种命名格式错误： 机种名称-配方编号, 配方编号为阿拉伯数字"})

        db_aircraft.aircraft = aircraft

    if route_id is not None and int(route_id) != db_aircraft.route_id:
        db_route: Union[Routes, None] = g.session.query(Routes).filter(Routes.id == route_id).first()
        if db_route is None:
            g.session.rollback()
            return jsonify({'status': 4003, "msg": "没有找到工艺路劲, 禁止修改"})
        ft_ids_new = []
        route_new = json.loads(db_route.route)
        routes_new = route_new.get("data")
        for itr1 in routes_new:
            second_rts: list = itr1.get("ft_ids")
            for itr2 in second_rts:
                ft_ids_new.append(itr2)
        ft_ids_new: list = list(set(ft_ids_new))

        db_route_old: Routes = g.session.query(Routes).filter(Routes.id == db_aircraft.route_id).first()
        ft_ids_old: list = []
        route_old = json.loads(db_route_old.route)
        routes_old = route_old.get("data")
        for index1, itr1 in enumerate(routes_old):
            second_rts: list = itr1.get("ft_ids")
            for itr2 in second_rts:
                ft_ids_old.append(itr2)
        ft_ids_old: list = list(set(ft_ids_old))

        same_itr: list = [x for x in ft_ids_new if x in ft_ids_old]
        remove_itr: list = []
        for itr in ft_ids_old:
            if itr not in same_itr:
                remove_itr.append(itr)

        for itr in remove_itr:
            g.session.query(Craft).filter(and_(Craft.aircraft_id == aircraft_id, Craft.facility_id == itr)).delete()
        db_aircraft.route_id = route_id
        g.session.commit()

        for ft_id in ft_ids_new:
            db_craft_init_all: List[CraftInit] = g.session.query(CraftInit).filter(
                                                    CraftInit.ft_id == ft_id
                                                ).order_by(CraftInit.id).all()

            db_craft_all: List[Craft] = g.session.query(Craft).filter(
                                            Craft.facility_id == ft_id,
                                            Craft.aircraft_id == db_aircraft.id
                                        ).order_by(Craft.id).all()
            for index, db_craft_init in enumerate(db_craft_init_all):
                insert_bool: bool = False
                for db_craft in db_craft_all:
                    if db_craft_init.address == db_craft.address:
                        insert_bool = True
                if insert_bool is False:
                    g.session.add(Craft(
                        facility_id=ft_id,
                        aircraft_id=db_aircraft.id,
                        address=db_craft_init.address,
                        types=db_craft_init.types,
                        describe=db_craft_init.describe,
                        write=None
                    ))
    if specification is not None:
        db_aircraft.specification = specification

    g.session.commit()
    return jsonify({'status': 200, 'msg': "修改参数成功"})


@api_routes.route("/aircraft", methods=["DELETE"])
@certification(auth=True, role=None)
def func_aircraft_delete_api():
    """
    删除机种, 完成API开发
    http://127.0.0.1:8080/api/aircraft
    Content-Type=application/json
    methods=["DELETE"]
    {
    "aircraft_id":     int       ****  机种数据库ID
    }
    :return:
        {'status': 4001, "msg": "客户端错误，未找到机种"}
        {'status': 200, 'msg': "删除机种成功"}
    ---
    tags:
      - 机种管理
    """
    data: dict = request.get_json()
    aircraft_id: Union[int, None] = data.get("aircraft_id")

    if aircraft_id is None:
        abort(400)

    db_aircraft: Union[Aircraft, None] = g.session.query(Aircraft).filter(Aircraft.id == aircraft_id).first()
    if not db_aircraft:
        return jsonify({'status': 4001, "msg": "客户端错误，未找到机种"})

    db_task: Union[Tasks, None] = g.session.query(Tasks).filter(Tasks.aircraft_id == aircraft_id).first()
    if db_task is not None:
        return jsonify({'status': 4002, "msg": "该机种已生产工单，无法删除"})

    g.session.query(Craft).filter(and_(Craft.aircraft_id == db_aircraft.id)).delete()
    g.session.commit()
    g.session.query(Aircraft).filter(Aircraft.id == aircraft_id).delete()
    g.session.commit()

    context_logs(name="删除机种", obsolescence=None, data=json.dumps({"aircraft_id": aircraft_id}))

    return jsonify({'status': 200, 'msg': "删除机种成功"})

